package com.jt.config;

import com.jt.util.JwtUtil;
import com.jt.util.WebUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;


import java.util.*;

/**构建配置安全对象
 * 1)认证规则(哪些资源必须认证才可访问)
 * 2)加密规则(添加用户时密码写到了数据库,登录时要将输入的密码与数据查询出的密码进行比对)
 * 3)认证成功怎么处理?(跳转页面,返回json)
 * 4)认证失败怎么处理?(跳转页面,返回json)
 * 5)没有登录就去访问资源系统怎么处理?(返回登录页面,返回json)
 * */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    /**密码加密*/
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //1.关闭跨域攻击
        http.csrf().disable();
        //2.配置form认证
        http.formLogin()
                //登录成功怎么处理?(向客户端返回json)
                .successHandler(successHandler())//登陆成功
                //登录失败怎么处理?(向客户端返回json)
                .failureHandler(failureHandler());//登陆失败
        //假如某个资源必须认证才可访问,那没有认证怎么办?(返回json)
        http.exceptionHandling()
                .authenticationEntryPoint(entryPoint());//提示要认证
        //3.所有资源都要认证
        http.authorizeRequests()
                .antMatchers("/auth/info")
                .permitAll()
                .anyRequest()//所有请求
                .authenticated();//必须认证
    }

    /**
     * 登陆成功以后的处理器
     */
    private AuthenticationSuccessHandler successHandler() {
        return (request, response, authentication) -> {
            Map<String, Object> map = new HashMap<>();
            map.put("state", 200);
            map.put("message", "login OK");
            //创建令牌(JWT令牌)
            Map<String, Object> userInfo = new HashMap<>();
            //获取用户身份(包含了认证和授权信息)
            User user = (User) authentication.getPrincipal();
            //将用户名存入集合
            userInfo.put("username", user.getUsername());//登陆用户名
            List<String> authoritiesList = new ArrayList<>();
            //获取用户权限
            Collection<GrantedAuthority> authorities =
                    user.getAuthorities();
            for(GrantedAuthority a:authorities){
                authoritiesList.add(a.getAuthority());//sys:res:create
            }
            //将用户权限存入userInfo集合
            userInfo.put("authorities", authoritiesList);
            //创建token
            String token = JwtUtil.generateToken(userInfo);
            map.put("token", token);
            WebUtils.writeJsonToClient(response, map);
        };
    }

    /**
     * 登陆失败的处理器
     */
    private AuthenticationFailureHandler failureHandler() {
        return (request,response,exception) -> {
            Map<String, Object> map = new HashMap<>();
            map.put("state", 500);
            map.put("msg", "username or password error");
            WebUtils.writeJsonToClient(response, map);
        };
    }

    /**
     * 假如没有登录访问资源时给出提示
     */
    private AuthenticationEntryPoint entryPoint() {
        return (request,response,exception) -> {
            Map<String, Object> map = new HashMap<>();
            map.put("state", 500);
            map.put("msg", "请先登陆认证");
            WebUtils.writeJsonToClient(response, map);
        };
    }
}
